package sample.com.imagecompress.util;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.media.ExifInterface;
import android.media.ThumbnailUtils;
import android.os.Build;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by shangdawei on 2017/8/15.
 */

public class ImageCompress {

    private final static String TAG = "COMPRESS";

    public static int pictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    public static Bitmap rotate(Bitmap bitmap, int degrees) {
        if (degrees == 0) {
            return bitmap;
        }
        if (degrees != 0 && bitmap != null) {
            Matrix m = new Matrix();
            m.setRotate(degrees, (float) bitmap.getWidth(), (float) bitmap.getHeight());
            try {
                Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
                if (bitmap != b2) {
                    bitmap.recycle();
                    bitmap = b2;
                }
            } catch (OutOfMemoryError ex) {
            }
        }
        return bitmap;
    }

    public static void compressImage(Bitmap image, File saveFile, int maxSize) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int quality = 100;
        Log.d(TAG, "baosLength =" + baos.toByteArray().length);
        // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
        while (baos.toByteArray().length / 1024 > maxSize) {
            Log.d(TAG, "sizeLength = " + baos.toByteArray().length / 1024);
            // 重置baos即清空baos
            baos.reset();
            // 每次都减少10
            quality -= 2;
            // 这里压缩options%，把压缩后的数据存放到baos中
            Log.d(TAG, "options =" + quality);
            image.compress(Bitmap.CompressFormat.JPEG, quality, baos);
            Log.d(TAG, "baosLength2 =" + baos.toByteArray().length);
            Log.d(TAG, "sizeLength2 = " + baos.toByteArray().length / 1024);
        }
        // 把压缩后的数据baos存放到ByteArrayInputStream中
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        // 把ByteArrayInputStream数据生成图片
        Bitmap bitmap = BitmapFactory.decodeStream(bais, null, null);

        if (saveFile != null) {
            saveImage(bitmap, saveFile, quality);
        }

        try {
            if (baos != null) {
                baos.flush();
                baos.close();
            }

            if (bais != null) {
                bais.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        bitmap.recycle();
        bitmap = null;
    }

    public static Bitmap withWatermark(Bitmap bitmap, String watermark) {
        int x = 10, y = 0;
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
        paint.setColor(Color.parseColor("#FEFEFE"));
        paint.setTextSize(16);// 字体大小
        paint.setTypeface(Typeface.DEFAULT);// 采用默认的宽度

        String[] texts = watermark.split("\n");
        int maxWidth = 0;
        int totalHeight = 0;
        float maxWidthF = 0;
        float totalHeightF = 0;
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float fontHeight = fontMetrics.bottom - fontMetrics.top;
        totalHeightF = fontHeight;
        Rect rect = new Rect();
        for (String text : texts) {
            float fontWidth = paint.measureText(text);
            if (fontWidth > maxWidthF) {
                maxWidthF = fontWidth;
            }
            // totalHeightF += fontHeight;

            paint.getTextBounds(text, 0, text.length(), rect);
            if (rect.width() > maxWidth) {
                maxWidth = rect.width();
            }
            totalHeight += rect.height();
        }

        paint.setAntiAlias(true);
        Bitmap newBmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(newBmp);
        canvas.drawBitmap(bitmap, 0, 0, null);

        Bitmap watermarkBmp = Bitmap.createBitmap((int) maxWidthF, (int) totalHeightF, Config.ARGB_8888);
        Paint wmPaint = new Paint();
        wmPaint.setColor(Color.BLACK);
        wmPaint.setAlpha(90);
        wmPaint.setStyle(Paint.Style.FILL);
        Canvas wmCanvas = new Canvas(watermarkBmp);
        wmCanvas.drawRect(0, 0, (int) maxWidthF, (int) totalHeightF, wmPaint);
        canvas.drawBitmap(watermarkBmp, 0, 0, null);

        String[] lines = watermark.split("\n");
        int top = y + 20;
        for (String t : lines) {
            t = t.replace("\r", "");
            canvas.drawText(t, x, top, paint);
            top += paint.getTextSize() + 10;
        }
        
        // canvas.save(Canvas.ALL_SAVE_FLAG); // 在 android P 上会报错，修改使用 canvas.save();
        canvas.save();
        return newBmp;
    }

    public static void saveImage(Bitmap bitmap, File file, int quality) {
        if (quality <= 0) {
            quality = 100;
        }
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(file));
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.flush();
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 获取缩略图，会裁减
    private static Bitmap getThumbnail(Bitmap bitmap, int width, int height) {
        Bitmap resizeBmp = ThumbnailUtils.extractThumbnail(bitmap, width, height);
        return resizeBmp;
    }

    public static Bitmap sampleImage(String srcPath, int newWidth, int newHeight) {

        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片，此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        // 默认值是ARGB_8888，在这个模式下，一个像素点占用4bytes空间，
        // 对透明度不做要求的话，一般采用RGB_565模式，这个模式下一个像素点占用2bytes
        newOpts.inPreferredConfig = Config.RGB_565;
        // 表示是否在解码时图片有更高的品质，仅用于JPEG格式。
        // 如果设置为true，则图片会有更高的品质，但是会解码速度会很慢
        newOpts.inPreferQualityOverSpeed = true;
        newOpts.inDither = true;

        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空
        newOpts.inJustDecodeBounds = false;

        // int w = newOpts.outWidth;
        // int h = newOpts.outHeight;
        //
        // // 现在主流手机比较多是800*480分辨率，所以高和宽我们设置为
        // float hh = newHeight;
        // float ww = newWidth;
        // // 缩放比。由于是固定比例缩放，只用高或者宽其中一个数据进行计算即可
        // int be = 1;// be=1表示不缩放
        // if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
        //     be = (int) (newOpts.outWidth / ww);
        // } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
        //     be = (int) (newOpts.outHeight / hh);
        // }
        // if (be <= 0) {
        //     be = 1;
        // }
        int degree = pictureDegree(srcPath);
        // if (degree != 0) {
        //     if (degree == 90) {
        //         int temp = newWidth;
        //         newWidth = newHeight;
        //         newHeight = temp;
        //     }
        // }

        // newOpts.inSampleSize = be;// 设置缩放比例
        newOpts.inSampleSize = calSampleSize(newOpts, newWidth, newHeight);// 设置缩放比例
        // 重新读入图片，注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(srcPath, newOpts);

        if (degree != 0) {
            bitmap = rotate(bitmap, degree);
        }

        return bitmap;
    }

    public static Bitmap ratioImage(String srcPath, int maxWidth, int maxHeight) {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(srcPath, options);

        // 获得图片的宽高
        int actualHeight = options.outHeight;
        int actualWidth = options.outWidth;

        int degree = pictureDegree(srcPath);
        if (degree != 0) {
            if (degree == 90 || degree == 270) {
                int tempWidth = actualWidth;
                actualWidth = actualHeight;
                actualHeight = tempWidth;
            }
        }

        // 实际图片比例
        float imgRatio = (float) actualWidth / actualHeight;
        // 想要的最大图片比例
        float maxRatio = (float) maxWidth / maxHeight;

        // 如果图片真实宽高里的某一个比设定的最大宽高大,才进行比例压缩
        if (actualHeight > maxHeight || actualWidth > maxWidth) {
            if (imgRatio < maxRatio) {
                imgRatio = (float) maxHeight / actualHeight;
                actualWidth = (int) (imgRatio * actualWidth);
                actualHeight = maxHeight;
            } else if (imgRatio > maxRatio) {
                imgRatio = (float) maxWidth / actualWidth;
                actualHeight = (int) (imgRatio * actualHeight);
                actualWidth = maxWidth;
            } else {
                actualHeight = maxHeight;
                actualWidth = maxWidth;
            }
        }

        // 先进行采样率压缩
        Bitmap bmp = sampleImage(srcPath, actualWidth, actualHeight);

        Bitmap scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Config.RGB_565);

        // 计算缩放比例
        float ratioX = actualWidth / (float) bmp.getWidth();
        float ratioY = actualHeight / (float) bmp.getHeight();
        // float middleX = actualWidth / 2.0f;
        // float middleY = actualHeight / 2.0f;

        // 取得想要缩放的matrix参数
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(ratioX, ratioY, 0, 0);
        Canvas canvas = new Canvas(scaledBitmap);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(bmp, 0.0F, 0.0F, new Paint(Paint.FILTER_BITMAP_FLAG));
        Matrix matrix = new Matrix();
        // 得到新的图片
        scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);

        return scaledBitmap;
    }

    public static Bitmap fixedImage(Bitmap bmp, int newWidth, int newHeight) {

        // 获得图片的宽高
        int width = bmp.getWidth();
        int height = bmp.getHeight();
        // 计算缩放比例
        float scaleWidth = (float) newWidth / (float) width;
        float scaleHeight = (float) newHeight / (float) height;
        // 取得想要缩放的matrix参数
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // 得到新的图片
        Bitmap newBmp = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true);
        return newBmp;
    }

    public static int calSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight) {
        int inSampleSize = 1;
        //原始宽高
        int rawWidth = options.outWidth;
        int rawHeight = options.outHeight;
        if (rawWidth > dstWidth || rawHeight > dstHeight) {
            //得到图片比目标控件高大的倍数
            float ratioHeight = (float) rawHeight / dstHeight;
            //得到图片比目标控件宽大的倍数
            float ratioWidth = (float) rawWidth / dstWidth;
            //两者中取最小的以便于覆盖控件不失真
            inSampleSize = (int) Math.max(ratioWidth, ratioHeight);
        }
        if (inSampleSize <= 0) {
            inSampleSize = 1;
        }

        if (inSampleSize == 2) {
            inSampleSize = 2;
        } else if ((inSampleSize > 2 && inSampleSize <= 4) || inSampleSize - 2 <= 4) {
            inSampleSize = 4;
        } else /* if (sampleSize > 4 && sampleSize <= 8)*/ {
            inSampleSize = 8;
        }

        return inSampleSize;
    }

    public static BitmapFactory.Options getBmpOptions(String srcPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片，此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空
        return newOpts;
    }
}
